import os

from flask import current_app

from app.model.user.wtrees_group import GroupModel
from app.serve.wtrees.db import db, func
from werkzeug.security import check_password_hash, generate_password_hash
from app.model.user.wtrees_user import UserModel
from app.model.user.wtrees_user_group import UserGroupModel
from app.model.user.wtrees_user_identity import UserIdentityInterface
from app.util.exception import WtreesReturn, ErrorType, WtreesError

from app.util.page import Page


class UserServe(UserModel):

    def _set_fields(self):
        self._exclude = ["delete_time", "create_time", "update_time"]

    @classmethod
    def user_all(cls):
        query = cls.query
        page = Page(query)
        for user in page.items:
            setattr(user, "group", cls.user_group(user.id))

        return page

    @classmethod
    def user_creation_group(cls, user_id, group_id=None):
        user_group = UserGroupModel.get(user_id=user_id, group_id=group_id)
        if user_group:
            user_group.group_id = group_id
            db.session.add(user_group)
        else:
            UserGroupModel.create(user_id=user_id, group_id=group_id)

    @classmethod
    def user_creation(cls, data=None):
        if cls.get(username=data['username']):
            print(1)
        # raise Duplicated("用户名重复，请重新输入")
        user = cls.create(username=data['username'], nickname=data['nickname'], flush=True)
        UserIdentityInterface(user_id=user.id, credential=generate_password_hash(data['password']),
                              identity_type="USERNAME_PASSWORD")
        if data['group_id']:
            cls.user_creation_group(user.id, data['group_id'])
        db.session.commit()

        # return Success("用户创建成功")

    @classmethod
    def user_alter(cls, data=None):
        if cls.get(username=data['username']):
            print(1)
            # raise Duplicated("用户名重复，请重新输入")
        user = cls.get(id=data['id']).update(username=data['username'], nickname=data['nickname'],
                                             avatar=['avatar'], email=['email'])
        if data['group_id']:
            cls.user_creation_group(user.id, data['group_id'])
        db.session.commit()

    @classmethod
    def count_by_username(cls, username) -> int:
        result = db.session.query(func.count(cls.id)).filter(
            cls.username == username, cls.delete_time == None
        )
        count = result.scalar()
        return count

    @classmethod
    def count_by_email(cls, email) -> int:
        result = db.session.query(func.count(cls.id)).filter(
            cls.email == email, cls.delete_time == None
        )
        count = result.scalar()
        return count

    @classmethod
    def user_group(cls, user_id) -> list:
        user_group = db.session.query(GroupModel).select_from(UserGroupModel) \
            .outerjoin(GroupModel, GroupModel.id == UserGroupModel.group_id) \
            .filter(UserGroupModel.user_id == user_id).first()
        if user_group:
            return user_group.get_info()

    def reset_password(self, new_password):
        self.password = new_password

    def change_password(self, old_password, new_password):
        if self.check_password(old_password):
            self.password = new_password
            return True
        return False

    @property
    def avatar(self):
        site_domain = current_app.config.get(
            "SITE_DOMAIN",
            "http://{host}:{port}".format(
                host=current_app.config.get("FLASK_RUN_HOST", "127.0.0.1"),
                port=current_app.config.get("FLASK_RUN_PORT", "5000"),
            ),
        )

        if self._avatar is not None:
            return site_domain + os.path.join(current_app.static_url_path, self._avatar)

    @classmethod
    def count_by_id(cls, uid) -> int:
        result = db.session.query(func.count(cls.id)).filter(
            cls.id == uid, cls.delete_time == None
        )
        count = result.scalar()
        return count

    @property
    def is_active(self):
        return True

    @property
    def password(self):
        return UserIdentityInterface.get(user_id=self.id).credential

    @password.setter
    def password(self, raw):
        user_identity = UserIdentityInterface.get(user_id=self.id)
        if user_identity:
            user_identity.credential = generate_password_hash(raw)
            user_identity.update(synchronize_session=False)
        else:
            user_identity = UserIdentityInterface()
            user_identity.user_id = self.id
            user_identity.identity_type = "USERNAME_PASSWORD"
            user_identity.identity = "root"
            user_identity.credential = generate_password_hash(raw)
            db.session.add(user_identity)

    def check_password(self, raw):
        return check_password_hash(self.password, raw)

    @classmethod
    def verify(cls, username, password):
        user = cls.query.filter_by(username=username).first()
        if user is None or user.delete_time is not None:
            # raise WtreesError(ErrorType.user_does_not)
            raise WtreesError(ErrorType.user_does_not)
        if not user.check_password(password):
            raise WtreesError(ErrorType.wrong_password)
        return user

    def _set_fields(self):
        self._exclude = ["delete_time", "create_time", "update_time"]

    @classmethod
    def count_by_username(cls, username) -> int:
        result = db.session.query(func.count(cls.id)).filter(
            cls.username == username, cls.delete_time == None
        )
        count = result.scalar()
        return count

    @classmethod
    def count_by_email(cls, email) -> int:
        result = db.session.query(func.count(cls.id)).filter(
            cls.email == email, cls.delete_time == None
        )
        count = result.scalar()
        return count

    def reset_password(self, new_password):
        self.password = new_password

    def change_password(self, old_password, new_password):
        if self.check_password(old_password):
            self.password = new_password
            return True
        return False
